package com.cmsz.order.controller;

import java.io.IOException;
import java.util.Base64;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.ServletException;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.ClientProtocolException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cmsz.cashier.mapper.WxAppIdSecretMapper;
import com.cmsz.order.remote.BetterRemoteService;
import com.cmsz.order.remote.SignResult;
import com.cmsz.framework.http.HttpClient;
import com.cmsz.framework.log.LogHandler;
import com.cmsz.framework.util.JsonUtil;
import com.cmsz.framework.util.KeyValueUtil;
import com.cmsz.framework.util.XmlUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
@RequestMapping("/h5")
public class H5WxOpenIdACtion {
	
	private static LogHandler logger = LogHandler.getLogger(H5WxOpenIdACtion.class);
	@Value("${weixin.openid.url}")
	private String wxOauthUrlForOpenid;  
	@Autowired
	private HttpClient httpClient;
	@Autowired
	WxAppIdSecretMapper wxAppIdSecretMapper;
	@Resource(name="BankSecurityRemoting")
	private BetterRemoteService betterRemoteService;
	@Value("${orderUrl}")
	private String orderUrl;
	@ResponseBody
	@RequestMapping(value = "/getopenid",produces = "text/html; charset=utf-8", method = { RequestMethod.POST,
			RequestMethod.GET })
	public String getcode(ModelMap map, String code, String state, String orderdata) throws IOException, ServletException {
		try {
			String orderXml = new String(Base64.getDecoder().decode(orderdata));
			logger.info("收银台|WxOpenIdController|接收到微信响应code",null);
			logger.messageReceive("H5网站|H5WxOpenIdACtion|接收到微信响应base64 orderXml:"+orderXml);
			logger.messageReceive("H5网站|H5WxOpenIdACtion|接收到微信响应code："+code+",state:"+state+",orderXml:"+orderXml);
			checkSignForXml(orderXml);
			if(StringUtils.isBlank(code)){
				throw new RuntimeException("获取code为空");
			}
			String openId = getOpenIdFormWx(code,orderXml);
			logger.info("收银台|WxOpenIdController|接收到openID：" + openId,null);
			logger.messageReceive("H5网站|H5WxOpenIdACtion|接收到openID：" + openId);
			if (StringUtils.isBlank(openId)) {
				throw new RuntimeException("获取openid为空");
			}
			orderXml = XmlUtils.relaceNodeContent("<WeiXinOpenId>", "</WeiXinOpenId>", openId, orderXml);
			orderXml = signForxml(orderXml);
			
			String frontRsp = sendToFront(orderXml);
			logger.messageSend("H5网站|H5WxOpenIdACtion|接收到响应报文：" + frontRsp);
			logger.info("H5网站|H5WxOpenIdACtion|发送请求报文完成",null);
			
			checkSignForXml(frontRsp);
			logger.info("H5网站|H5WxOpenIdACtion|统一支付响应报文验签完成",null);
			
			checkCode(frontRsp);
			logger.info("H5网站|H5WxOpenIdACtion|统一支付响应报文参数校验完成",null);
			
			String parameters = genParam(frontRsp);
			logger.info("H5网站|H5WxOpenIdACtion|响应微信公众号支付",null);
			logger.messageSend("H5网站|H5WxOpenIdACtion|响应微信公众号支付：" + parameters);
			map.addAttribute("parameters", parameters);
			return "page/wxjsapi";
		} catch (Exception e) {
			logger.error("H5网站|H5WxOpenIdACtion|提交订单失败:"+e.getMessage(), e);
			// todo return error
			return null;
		}
	   
	}

	
	
	private String getOpenIdFormWx(String code, String orderXml) {
//		https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
		String openId = "";
		try {
			String tokenUrl = wxOauthUrlForOpenid;
			String appId = XmlUtils.parseNodeValueFromXml("<WeiXinAppId>", "</WeiXinAppId>", orderXml);
			String wxsecret = wxAppIdSecretMapper.selectSecretByAppId(appId);
			if(StringUtils.isBlank(wxsecret)){
				throw new RuntimeException("无法找到APPID:"+appId+"对应的secret");
			}
			String data = "appid="+appId+"&secret="+wxsecret+"&code="
					+code+"&grant_type=authorization_code";
			logger.info("H5网站|H5WxOpenIdACtion|向微信请求获取token完成",null);
			logger.messageSend("H5网站|H5WxOpenIdACtion|向微信请求获取token：" + data);
			String rspJson = httpClient.sendStringMsg(tokenUrl, data);
			logger.info("H5网站|H5WxOpenIdACtion|接收到微信token响应完成",null);
			logger.messageReceive("H5网站|H5WxOpenIdACtion|接收到微信token响应："+rspJson);
			ObjectMapper mapper = new ObjectMapper();
			JsonNode node= mapper.readTree(rspJson); 
			/**
			 * {
				   "access_token":"ACCESS_TOKEN",
				   "expires_in":7200,
				   "refresh_token":"REFRESH_TOKEN",
				   "openid":"OPENID",
				   "scope":"SCOPE",
				   "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
				}   
			 */
			openId = node.get("openid").toString();
			openId = openId.substring(openId.indexOf("\"")+1,openId.lastIndexOf("\""));
		} catch (Exception e) {
			throw new RuntimeException("获取微信用户openID失败"+e.getMessage(),e);
		}
		return openId;
	}
	
	/**
	 * 对商户请求数据验签
	 * @param orderXml
	 */
	private void checkSignForXml(String orderXml) {
		StringBuilder plainText = new StringBuilder();
		String cerId = XmlUtils.parseNodeValueFromXml("<CerID>", "</CerID>", orderXml);
		String signature = XmlUtils.parseNodeValueFromXml("<SignValue>", "</SignValue>", orderXml);
		String header = XmlUtils.parseNodeValueFromXml("<Header>", "</Header>", orderXml);
		String body = XmlUtils.parseNodeValueFromXml("<Body>", "</Body>", orderXml);
		plainText.append("<Header>").append(header).append("</Header>|<Body>").append(body).append("</Body>");
		try {
			if (betterRemoteService.verify(cerId, plainText.toString(), signature)) {
				return;
			}
		} catch (Exception e) {
			throw new RuntimeException("系統未知异常");
		}
	}
	
	/**
	 * 签名给统一支付，商户前置要验签
	 * @param orderXml
	 * @return
	 */
	private String signForxml(String orderXml) {
		StringBuilder plainText = new StringBuilder();
		String header = XmlUtils.parseNodeValueFromXml("<Header>", "</Header>", orderXml);
		String body = XmlUtils.parseNodeValueFromXml("<Body>", "</Body>", orderXml);
		plainText.append("<Header>").append(header).append("</Header>|<Body>").append(body).append("</Body>");
		try {
			String jsonStr = betterRemoteService.sign(null, plainText.toString());
			SignResult signResult = JsonUtil.jsonStr2Obj(jsonStr, SignResult.class);
			orderXml = XmlUtils.relaceNodeContent("<CerID>", "</CerID>", signResult.getCerId(), orderXml);
			orderXml = XmlUtils.relaceNodeContent("<SignValue>", "</SignValue>", signResult.getSignValue(), orderXml);
			return orderXml;
		} catch (Exception e) {
			throw new RuntimeException("系統未知异常");
		}
	}
	
	/**
	 * 检查统一支付返回码
	 * @param xml
	 */
	private void checkCode(String xml) {
		String rspCode = XmlUtils.parseNodeValueFromXml("<RspCode>", "</RspCode>", xml);
		if (!"010A00".equals(rspCode)) {
			throw new RuntimeException("商户前置返回失败：" + rspCode);
		}
		String resultCode = XmlUtils.parseNodeValueFromXml("<ResultCode>", "</ResultCode>", xml);
		if (!"014A17".equals(resultCode)) {
			throw new RuntimeException("商户前置返回失败：" + resultCode);
		}
	}
	
	private String sendToFront(String orderXml) throws ClientProtocolException, IOException {
		String merchantFrontRsp = httpClient.sendStringMsg(orderUrl, orderXml);
		if (StringUtils.isBlank(merchantFrontRsp)) {
			throw new RuntimeException("网络通讯异常");
		}
		return merchantFrontRsp;
	}
	
	/**
	 * 组装调起微信公众号支付所需参数
	 * json格式
	 * @param frontRsp
	 * @return
	 * @throws JsonProcessingException 
	 */
	private String genParam(String frontRsp) throws JsonProcessingException {
		String parameters = XmlUtils.parseNodeValueFromXml("<Parameters><![CDATA[", "]]></Parameters>", frontRsp);
		Map<String, String>rspMap = KeyValueUtil.keyValueStringToMap(parameters);
		
		ObjectMapper mapper = new ObjectMapper();
		String paramJson = mapper.writeValueAsString(rspMap);
		return paramJson;
	}
}
